#ifndef BLOCKSTORAGE_H_
#define BLOCKSTORAGE_H_

#include <map>
#include <queue>
#include <set>
#include "mpi.h"
#include "Block.h"
#include "DataServer.h"

class BlockStorage {
public:
    virtual void startGettingBlock(int block_id);
    virtual void waitForBlocksAvailability();
    virtual bool areAllBlocksAvailable();
    
    virtual Block* getBlock(int block_id) { return current_blocks[block_id]; }
    
    virtual void nextIteration();
    
    virtual void startServingBlocks() { block_server.start(); }
    virtual void stopServingBlocks() { block_server.stop(); }
    
    BlockStorage();
    ~BlockStorage();
    
protected:
    class BlockServer : public DataServer {
    public:
        void setBlockSource(std :: map<int, Block*>* block_source) {
            this -> block_source = block_source;
        }
    
    protected:
        void listenForRequest();
        void sendResponse();
        
        int requested_block_id;
        std :: map<int, Block*>* block_source;
    };
    
    virtual void deleteUnusedBlocks();
    virtual void setBlocksInUsage(std :: set<Block*>& in_usage);
    virtual void deleteOldBlocksExcept(std :: set<Block*>& blocks_in_usage);
    
    virtual void getFromLocalMemory(int block_id);
    virtual void downloadFromRemote(int block_id);
    
    virtual void addToStorage(Block* new_block);
    virtual bool isInLocalMemory(int block_id);
    virtual int findBlockLocation(int block_id);
    
    virtual Block* createBlock(int block_id) = 0;
    
    
    std :: queue<Block*> downloadsInProgress;
    std :: map<int, Block*> prev_blocks, current_blocks;
    BlockServer block_server;
};

#endif
